1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package sun.java2d.jules;
27
28 import java.awt.*;
29 import java.awt.geom.*;
30 import sun.awt.X11GraphicsEnvironment;
31 import sun.java2d.pipe.*;
32 import sun.java2d.xr.*;
33
34 public class JulesPathBuf {
35 static final double[] emptyDash = new double[0];
36
37 private static final byte CAIRO_PATH_OP_MOVE_TO = 0;
38 private static final byte CAIRO_PATH_OP_LINE_TO = 1;
39 private static final byte CAIRO_PATH_OP_CURVE_TO = 2;
40 private static final byte CAIRO_PATH_OP_CLOSE_PATH = 3;
41
42 private static final int CAIRO_FILL_RULE_WINDING = 0;
43 private static final int CAIRO_FILL_RULE_EVEN_ODD = 1;
44
45 GrowablePointArray points = new GrowablePointArray(128);
46 GrowableByteArray ops = new GrowableByteArray(1, 128);
47 int[] xTrapArray = new int[512];
48
49 private static final boolean isCairoAvailable;
50
51 static {
52 isCairoAvailable =
53 java.security.AccessController.doPrivileged(
54 new java.security.PrivilegedAction<Boolean>() {
55 public Boolean run() {
56 boolean loadSuccess = false;
57 if (X11GraphicsEnvironment.isXRenderAvailable()) {
58 try {
59 System.loadLibrary("jules");
60 loadSuccess = true;
61 if (X11GraphicsEnvironment.isXRenderVerbose()) {
62 System.out.println(
63 "Xrender: INFO: Jules library loaded");
64 }
65 } catch (UnsatisfiedLinkError ex) {
66 loadSuccess = false;
67 if (X11GraphicsEnvironment.isXRenderVerbose()) {
68 System.out.println(
69 "Xrender: INFO: Jules library not installed.");
70 }
71 }
72 }
73 return Boolean.valueOf(loadSuccess);
74 }
75 });
76 }
77
78 public static boolean isCairoAvailable() {
79 return isCairoAvailable;
80 }
81
82 public TrapezoidList tesselateFill(Shape s, AffineTransform at, Region clip) {
83 int windingRule = convertPathData(s, at);
84 xTrapArray[0] = 0;
85
86 xTrapArray = tesselateFillNative(points.getArray(), ops.getArray(),
87 points.getSize(), ops.getSize(),
88 xTrapArray, xTrapArray.length,
89 getCairoWindingRule(windingRule),
90 clip.getLoX(), clip.getLoY(),
91 clip.getHiX(), clip.getHiY());
92
93 return new TrapezoidList(xTrapArray);
94 }
95
96 public TrapezoidList tesselateStroke(Shape s, BasicStroke bs, boolean thin,
97 boolean adjust, boolean antialias,
98 AffineTransform at, Region clip) {
99
100 float lw;
101 if (thin) {
102 if (antialias) {
103 lw = 0.5f;
104 } else {
105 lw = 1.0f;
106 }
107 } else {
108 lw = bs.getLineWidth();
109 }
110
111 convertPathData(s, at);
112
113 double[] dashArray = floatToDoubleArray(bs.getDashArray());
114 xTrapArray[0] = 0;
115
116 xTrapArray =
117 tesselateStrokeNative(points.getArray(), ops.getArray(),
118 points.getSize(), ops.getSize(),
119 xTrapArray, xTrapArray.length, lw,
120 bs.getEndCap(), bs.getLineJoin(),
121 bs.getMiterLimit(), dashArray,
122 dashArray.length, bs.getDashPhase(),
123 1, 0, 0, 0, 1, 0,
124 clip.getLoX(), clip.getLoY(),
125 clip.getHiX(), clip.getHiY());
126
127 return new TrapezoidList(xTrapArray);
128 }
129
130 protected double[] floatToDoubleArray(float[] dashArrayFloat) {
131 double[] dashArrayDouble = emptyDash;
132 if (dashArrayFloat != null) {
133 dashArrayDouble = new double[dashArrayFloat.length];
134
135 for (int i = 0; i < dashArrayFloat.length; i++) {
136 dashArrayDouble[i] = dashArrayFloat[i];
137 }
138 }
139
140 return dashArrayDouble;
141 }
142
143 protected int convertPathData(Shape s, AffineTransform at) {
144 PathIterator pi = s.getPathIterator(at);
145
146 double[] coords = new double[6];
147 double currX = 0;
148 double currY = 0;
149
150 while (!pi.isDone()) {
151 int curOp = pi.currentSegment(coords);
152
153 int pointIndex;
154 switch (curOp) {
155
156 case PathIterator.SEG_MOVETO:
157 ops.addByte(CAIRO_PATH_OP_MOVE_TO);
158 pointIndex = points.getNextIndex();
159 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
160 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
161 currX = coords[0];
162 currY = coords[1];
163 break;
164
165 case PathIterator.SEG_LINETO:
166 ops.addByte(CAIRO_PATH_OP_LINE_TO);
167 pointIndex = points.getNextIndex();
168 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
169 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
170 currX = coords[0];
171 currY = coords[1];
172 break;
173
174
175
176
177
178
179
180 case PathIterator.SEG_QUADTO:
181 double x1 = coords[0];
182 double y1 = coords[1];
183 double x2, y2;
184 double x3 = coords[2];
185 double y3 = coords[3];
186
187 x2 = x1 + (x3 - x1) / 3;
188 y2 = y1 + (y3 - y1) / 3;
189 x1 = currX + 2 * (x1 - currX) / 3;
190 y1 =currY + 2 * (y1 - currY) / 3;
191
192 ops.addByte(CAIRO_PATH_OP_CURVE_TO);
193 pointIndex = points.getNextIndex();
194 points.setX(pointIndex, DoubleToCairoFixed(x1));
195 points.setY(pointIndex, DoubleToCairoFixed(y1));
196 pointIndex = points.getNextIndex();
197 points.setX(pointIndex, DoubleToCairoFixed(x2));
198 points.setY(pointIndex, DoubleToCairoFixed(y2));
199 pointIndex = points.getNextIndex();
200 points.setX(pointIndex, DoubleToCairoFixed(x3));
201 points.setY(pointIndex, DoubleToCairoFixed(y3));
202 currX = x3;
203 currY = y3;
204 break;
205
206 case PathIterator.SEG_CUBICTO:
207 ops.addByte(CAIRO_PATH_OP_CURVE_TO);
208 pointIndex = points.getNextIndex();
209 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
210 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
211 pointIndex = points.getNextIndex();
212 points.setX(pointIndex, DoubleToCairoFixed(coords[2]));
213 points.setY(pointIndex, DoubleToCairoFixed(coords[3]));
214 pointIndex = points.getNextIndex();
215 points.setX(pointIndex, DoubleToCairoFixed(coords[4]));
216 points.setY(pointIndex, DoubleToCairoFixed(coords[5]));
217 currX = coords[4];
218 currY = coords[5];
219 break;
220
221 case PathIterator.SEG_CLOSE:
222 ops.addByte(CAIRO_PATH_OP_CLOSE_PATH);
223 break;
224 }
225
226 pi.next();
227 }
228
229 return pi.getWindingRule();
230 }
231
232 private static native int[]
233 tesselateStrokeNative(int[] pointArray, byte[] ops,
234 int pointCnt, int opCnt,
235 int[] xTrapArray, int xTrapArrayLength,
236 double lineWidth, int lineCap, int lineJoin,
237 double miterLimit, double[] dashArray,
238 int dashCnt, double offset,
239 double m00, double m01, double m02,
240 double m10, double m11, double m12,
241 int clipLowX, int clipLowY,
242 int clipWidth, int clipHeight);
243
244 private static native int[]
245 tesselateFillNative(int[] pointArray, byte[] ops, int pointCnt,
246 int opCnt, int[] xTrapArray, int xTrapArrayLength,
247 int windingRule, int clipLowX, int clipLowY, int clipWidth, int clipHeight);
248
249 public void clear() {
250 points.clear();
251 ops.clear();
252 xTrapArray[0] = 0;
253 }
254
255 private static int DoubleToCairoFixed(double dbl) {
256 return (int) (dbl * 256);
257 }
258
259 private static int getCairoWindingRule(int j2dWindingRule) {
260 switch(j2dWindingRule) {
261 case PathIterator.WIND_EVEN_ODD:
262 return CAIRO_FILL_RULE_EVEN_ODD;
263
264 case PathIterator.WIND_NON_ZERO:
265 return CAIRO_FILL_RULE_WINDING;
266
267 default:
268 throw new IllegalArgumentException("Illegal Java2D winding rule specified");
269 }
270 }
271 }